# -*- coding: utf-8 -*-
from django.template.loader import get_template
from django.template import Template, Context
from django.shortcuts import render
from django.http import HttpResponse
import django.forms
import pdb
import datetime

from safeinside.path import MSLib, config

MSLib.glogger.at(MSLib.Logs.OBJECTS).setlevel(MSLib.SimpleLogger.INFO)
MSLib.glogger.at(MSLib.Logs.OBJECTS).setident('objects')

MSLib.glogger.at(MSLib.Logs.MSDB).setlevel(MSLib.SimpleLogger.INFO)
MSLib.glogger.at(MSLib.Logs.MSDB).setident('msdb')

REGIONS = \
[
 ('dev', 'Санкт-Петербург'),
 ('kar', 'Республика Карелия'),
]
REGIONS_NOSTR = \
[
 (REGIONS[0][0], REGIONS[0][0]),
 (REGIONS[1][0], REGIONS[1][0]),
]

VERSIONS = MSLib.CarOnlineDB_Templates().getSupportedFirmwares(config.get('main', 'firmware_path'))
VERSIONS = VERSIONS + [ ('default', 'оставить прошивку по-умолчанию'), ('fname', 'ввести имя файла')]

class ObjectsFilterForm(django.forms.Form):
    region = django.forms.ChoiceField(choices=REGIONS + [('all', 'все')], initial='все')
    enabled = django.forms.ChoiceField(choices=[('all', 'все'), ('enabled', 'включенные'), ('disabled', 'выключенные')], initial='все')
    test = django.forms.ChoiceField(choices=[('all', 'все'), ('test', 'тестовые'), ('normal', 'нормальные')], initial='все')
    objPCNId = django.forms.IntegerField(required=False)
    objPCNIdMin = django.forms.IntegerField(required=False)
    objPCNIdMax = django.forms.IntegerField(required=False)
    objMac = django.forms.CharField(required=False)
    objFirmware = django.forms.CharField(required=False)
    
class ObjectCreateForm(django.forms.Form):
    region = django.forms.ChoiceField(choices=REGIONS, initial='Санкт-Петербург')
    objMac = django.forms.CharField()
    objPCNId = django.forms.IntegerField()
    objNewFirmwareSelected = django.forms.ChoiceField(required=False, choices=VERSIONS, initial='оставить прошивку по-умолчанию')
    objNewFirmwareEntered = django.forms.CharField(required=False)
    
class ObjectModifyForm(django.forms.Form):
    objOldRegion = django.forms.CharField(widget=django.forms.TextInput(attrs={'readonly':'readonly'}))
    objOldPCNId = django.forms.IntegerField(widget=django.forms.NumberInput(attrs={'readonly':'readonly'}))
    objOldLogin = django.forms.CharField(widget=django.forms.TextInput(attrs={'readonly':'readonly'}))
    objMSId = django.forms.IntegerField(widget=django.forms.NumberInput(attrs={'readonly':'readonly'}))
    objOldFirmware = django.forms.CharField(widget=django.forms.TextInput(attrs={'readonly':'readonly'}))
    objCommand = django.forms.CharField()
    objNewFirmwareSelected = django.forms.ChoiceField(required=False, choices=VERSIONS, initial='оставить прошивку по-умолчанию')
    objNewFirmwareEntered = django.forms.CharField(required=False)
    objNewRegion = django.forms.ChoiceField(choices=REGIONS_NOSTR, initial='', required=False)
    objNewPCNId = django.forms.IntegerField(required=False)
    objNewLogin = django.forms.CharField(required=False)
    
class ObjectPhotosForm(django.forms.Form):
    daysBack = django.forms.IntegerField()


dbconfig = \
{
 'host': config.get('msdb', 'host'),
 'port': config.get('msdb', 'port'),
 'dbname' : config.get('msdb', 'dbname'),
 'user': config.get('msdb', 'user'),
 'password': config.get('msdb', 'pwd'),
}

photodbconfig = \
{
 'host': config.get('msphotodb', 'host'),
 'port': config.get('msphotodb', 'port'),
 'dbname': config.get('msphotodb', 'dbname'),
 'user': config.get('msphotodb', 'user'),
 'password': config.get('msphotodb', 'pwd'),
}

def hello(request):
    return render(request, 'safeinside/hello.html', {})

def createFilter(mode=None, region=None):
    init = \
    {
     'region':'all',
     'enabled':'all',
     'test':'all',
    }
    if mode == 'all':
        pass
    elif mode == 'normal':
        init['test'] = 'normal'
        init['enabled'] = 'enabled'
    elif mode == 'test':
        init['test'] = 'test'
        init['enabled'] = 'enabled'
    elif mode == 'disabled':
        init['enabled'] = 'disabled'
    elif mode == 'enabled':
        init['enabled'] = 'enabled'

    if region is not None:
        init['region'] = region
        
    filter = ObjectsFilterForm(init)
    return filter
    
def getObjects(request, params, filter=None):
    if filter is None:        
        if request.method == 'GET':
            params['filter_objects'] = ObjectsFilterForm()
        else:
            params['filter_objects'] = ObjectsFilterForm(request.POST)
    else:
        params['filter_objects'] = filter
        
    params['request_path'] = str(request.path)
    params['request_region'] = 'all'
    
    all = MSLib.Objects()
    MSLib.CarOnlineDB(dbconfig).objectsLoad(all)
    all.filterNormal(config.get('main', 'normal_objects'))
    params['objs_all'] = all
    
    if params['filter_objects'].is_valid():
        data = params['filter_objects'].cleaned_data
        
        filter_region = None
        if 'region' in data and data['region'] is not None and data['region'] != 'all':
            filter_region = data['region']
            params['request_region'] = filter_region
        
        filter_enabled = None
        if 'enabled' in data and data['enabled'] is not None and data['enabled'] != 'all':
            if data['enabled'] == 'enabled':
                filter_enabled = True
            elif data['enabled'] == 'disabled':
                filter_enabled = False
                
        filter_test = None
        if 'test' in data and data['test'] is not None and data['test'] != 'all':
            if data['test'] == 'test':
                filter_test = True
            elif data['test'] == 'normal':
                filter_test = False
                
        filter_pcnid = None
        if 'objPCNId' in data and data['objPCNId'] is not None and data['objPCNId'] > 0:
            filter_pcnid = data['objPCNId']
            
        if filter_pcnid is None \
                and 'objPCNIdMin' in data and data['objPCNIdMin'] is not None and data['objPCNIdMin'] >= 0 \
                and 'objPCNIdMax' in data and data['objPCNIdMax'] is not None and data['objPCNIdMax'] > 0 \
                and data['objPCNIdMin'] < data['objPCNIdMax']:
            filter_pcnid = [data['objPCNIdMin'], data['objPCNIdMax']]
            
        filter_mac = None
        if 'objMac' in data and data['objMac'] is not None and len(data['objMac']) > 0:
            filter_mac = data['objMac']            

        if filter_pcnid is not None:
            params['objs'] = all.sliceTargetId(filter_pcnid, filter_region, filter_enabled, filter_test)
        elif filter_mac is not None:
            params['objs'] = all.sliceMac(filter_mac, filter_region, filter_enabled, filter_test)
        else:
            filtered = all.filter(filter_region, filter_enabled, filter_test)
            objs = []
            for o in filtered:
                objs.append(o)
            params['objs'] = objs

def objectsList(request, mode=None):
    params = {}
    try:
        filter = None
        if mode is not None:
            filter = createFilter(mode=mode)
            params['mode'] = mode
    
        if filter is None:
            getObjects(request, params)
        else:
            getObjects(request, params, filter)
            
        if params['filter_objects'].is_valid():
            conn = MSLib.CarOnlineDB(dbconfig).getconnection()
            cur = conn.cursor()
            
            for o in params['objs']:
                query = 'SELECT TOP(1) deviceId,eventTime,db,nc FROM _gsm_data_internal WHERE deviceId=%s ORDER BY eventTime DESC' % (str(o.msid))
                cur.execute(query)
                buf = cur.fetchall()
                o.gsm_signal = '0'
                o.gsm_operator = 'Unknown'
                try:
                    o.gsm_signal = str(buf[0][2])
                    opid = int(buf[0][3])
                    o.gsm_operator = {1:'MTS', 2:'Megafon'}.get(opid, str(opid))
                except:
                    pass
    except Exception as err:
        params['error'] = str(err)
    return render(request, 'safeinside/list_of_objects.html', params)

def objectsOnlineOffline(request, mode):
    params = {}
    try:
        standalone = False
        if mode == 'normal_standalone':
            standalone = True
            mode = 'normal'

        filter = None
        if mode is not None:
            filter = createFilter(mode=mode)
            params['mode'] = mode

        if filter is None:
            getObjects(request, params)
        else:
            getObjects(request, params, filter)
        
        now = datetime.datetime.now()
        online = 0
        offline = 0
        for o in params['objs']:
            delta = now - o.lastEventTime
            delta = delta - datetime.timedelta(microseconds=delta.microseconds)
            o.delta = delta
            o.online = True
            o.ok = True
            if delta > datetime.timedelta(seconds=660):
                o.ok = False
            if delta > datetime.timedelta(seconds=3600*4):
                o.online = False
                offline += 1
            else:
                online += 1
            
        params['numonline'] = online
        params['numoffline'] = offline
        params['standalone'] = standalone
    except Exception as err:
        params['error'] = str(err)
    return render(request, 'safeinside/list_of_objects_simple.html', params)

def objectInfo(request, region, targetid, msg=None):
    params = {}
    try:
        filter = createFilter(region=region)
        getObjects(request, params, filter)
        params['obj'] = params['objs_all'].getTargetId(targetid=int(targetid), regions=region)
        
        if msg is not None: params['message'] = msg
        
        init = {}
        init['objOldRegion'] = params['obj'].targetregion
        init['objOldPCNId'] = params['obj'].targetid
        init['objOldLogin'] = params['obj'].caronline_login
        init['objMSId'] = params['obj'].msid
        init['objOldFirmware'] = params['obj'].versionSoftPGSM
        
        params['modify_object'] = ObjectModifyForm(init)
        
    except Exception as err:
        params['error'] = str(err)
    return render(request, 'safeinside/info_object.html', params)
    
def objectPhotos(request, region, targetid):
    params = {}
    try:
        filter = createFilter(region=region)
        getObjects(request, params, filter)
        params['obj'] = params['objs_all'].getTargetId(targetid=int(targetid), regions=region)
        
        daysback = 1
        params['photos_object'] = ObjectPhotosForm(request.POST)
        if params['photos_object'].is_valid():
            daysback = params['photos_object'].cleaned_data['daysBack']
        else:
            params['photos_object'] = ObjectPhotosForm({'daysBack':daysback})
        
        try:
            photos = MSLib.CarOnlineDB(photodbconfig).objectGetPhotos(params['obj'].msid, datetime.datetime.now() - datetime.timedelta(days=daysback))
            if len(photos) > 0:
                params['objPhotos'] = photos
        except Exception as err:
            params['error'] = 'Не удалось загрузить фотографии объекта - ' + str(err)
        
    except Exception as err:
        params['error'] = str(err)
    return render(request, 'safeinside/photo_object.html', params)

def objectCreate(request, mac=None):
    params = {}
    try:
        params['create_object'] = ObjectCreateForm(request.POST)
        if request.method == 'POST' and not params['create_object'].is_valid():
            raise RuntimeError('Введены некорректные данные. Исправьте, пожалуйста.')
            
        elif request.method == 'POST' and params['create_object'].is_valid():
            data = params['create_object'].cleaned_data
            if len(data['objMac']) > 0 and data['objPCNId'] > 0:
                login = str(data['region']) + str(data['objPCNId'])
                pwd = 'pass' + str(data['objPCNId'])
                done = MSLib.CarOnlineDB(dbconfig).objectCreate(data['region'], data['objPCNId'], data['objMac'])
                msg = 'Объект успешно добавлен как %s' % str(done[4])
                
                newfirmware = data['objNewFirmwareSelected']
                if newfirmware == 'custom':
                    newfirmware = data['objNewFirmwareEntered']
                if newfirmware != 'default' and newfirmware[0:4] == 'CID_':
                    MSLib.CarOnlineDB(dbconfig).objectReloadFirmware(done[3], newfirmware)
                    msg += ', инициирована перепрошивка на версию "%s"' % newfirmware
                return objectInfo(request, region=done[0], targetid=int(done[1]), msg=msg)
            raise RuntimeError('Введены некорректные данные. Исправьте, пожалуйста.')
            
        if mac is not None: params['create_object'] = ObjectCreateForm(initial={'objMac':mac})
    
    except Exception as err:
        params['error'] = str(err)
    return render(request, 'safeinside/object_create.html', params)
    
def objectModify(request):
    params = {}
    try:
        params['modify_object'] = ObjectModifyForm(request.POST)
        if request.method == 'POST' and params['modify_object'].is_valid():
            data = params['modify_object'].cleaned_data
            
            if 'objCommand' not in data or data['objCommand'] not in ['newlogin', 'newid', 'newregion', 'newfirmware', 'maketest', 'makenormal', 'enable', 'disable']:
                raise RuntimeError('Системная ошибка - неверная команда на модификацию объекта')
            
            filter = createFilter(region=data['objOldRegion'])
            getObjects(request, params, filter)
            obj = params['objs_all'].getTargetId(targetid=int(data['objOldPCNId']), regions=data['objOldRegion'])
            msg = 'Системная ошибка - команда "%s" не выполнена' % data['objCommand']
            
            try:
                if data['objCommand'] == 'newlogin':
                    oldlogin = str(obj.caronline_login)
                    newlogin = str(data['objNewLogin'])
                    MSLib.CarOnlineDB(dbconfig).objectRename(oldlogin, newlogin)
                    msg = 'Новый логин - объект "%s" переименован в "%s"' % (oldlogin, newlogin)
                    
                elif data['objCommand'] == 'newid':
                    oldlogin = str(obj.caronline_login)
                    newid = int(data['objNewPCNId'])
                    newlogin = obj.targetregion + str(newid)
                    if not obj.isEnabled:
                        newlogin += 'del'  
                    MSLib.CarOnlineDB(dbconfig).objectRename(oldlogin, newlogin)
                    obj.targetid = newid
                    msg = 'Переименование - объект "%s" переименован в "%s"' % (oldlogin, newlogin)
                
                elif data['objCommand'] == 'newregion':
                    oldlogin = str(obj.caronline_login)
                    newregion = str(data['objNewRegion'])
                    newlogin = newregion + str(obj.targetid)
                    if not obj.isEnabled:
                        newlogin += 'del'
                    MSLib.CarOnlineDB(dbconfig).objectRename(oldlogin, newlogin)
                    obj.targetregion = newregion
                    msg = 'Новый регион - объект "%s" переименован в "%s"' % (oldlogin, newlogin)
                
                elif data['objCommand'] == 'newfirmware':
                    newfirmware = data['objNewFirmwareSelected']
                    if newfirmware == 'custom':
                        newfirmware = data['objNewFirmwareEntered']
                    if newfirmware != 'default' and newfirmware[0:4] == 'CID_':
                        MSLib.CarOnlineDB(dbconfig).objectReloadFirmware(obj.msid, newfirmware)
                        msg = 'Перепрошивка на версию "%s" успешно инициирована для объекта "%s"' % (newfirmware, obj.caronline_login)
                
                elif data['objCommand'] == 'maketest':
                    if not obj.isTest:
                        MSLib.Objects.makeTest(config.get('main', 'normal_objects'), obj.targetid)
                        msg = 'Объект "%s" переведен в тестовые' % (obj.caronline_login)
                    
                elif data['objCommand'] == 'makenormal':
                    if obj.isTest:
                        MSLib.Objects.makeNormal(config.get('main', 'normal_objects'), obj.targetid)
                        msg = 'Объект "%s" переведен в нормальные' % (obj.caronline_login)
                        
                elif data['objCommand'] == 'enable':
                    if not obj.isEnabled:
                        oldlogin = str(obj.caronline_login)
                        newlogin = str(obj.targetregion) + str(obj.targetid)
                        MSLib.CarOnlineDB(dbconfig).objectRename(oldlogin, newlogin)
                        msg = 'Объект "%s" включен' % (newlogin)
                
                elif data['objCommand'] == 'disable':
                    if obj.isEnabled:
                        oldlogin = str(obj.caronline_login)
                        newlogin = str(obj.targetregion) + str(obj.targetid) + 'del'
                        MSLib.CarOnlineDB(dbconfig).objectRename(oldlogin, newlogin)
                        msg = 'Объект "%s" выключен' % (newlogin)
                        
            except Exception as err:
                msg += ':' + str(err)
                        
            return objectInfo(request, region=obj.targetregion, targetid=obj.targetid, msg=msg)

    except Exception as err:
        params['error'] = str(err)
    return render(request, 'safeinside/hello.html', params)

def oneObjectLogin(request):
    return render(request, 'safeinside/one_object_login.html', {'standalone':True})
def oneObject(request):
    params = {}
    getObjects(request, 'all', params)
    login   = request.REQUEST['objectLogin']
    pwd     = request.REQUEST['objectPassword']
    obj = None
    for o in params['objs_all'].all():
        if o.caronline_login == login and o.caronline_password == pwd:
            obj = o
    if obj != None:

        query1 = 'SELECT TOP(1) id,eventTime FROM _event_data_internal WHERE deviceId=%s ORDER BY eventTime DESC' % (str(obj.msid))
        query2 = 'SELECT TOP(1) id,eventTime,db,nc FROM _gsm_data_internal WHERE deviceId=%s ORDER BY eventTime DESC' % (str(obj.msid))

        conn = MSLib.CarOnlineDB(dbconfig).getconnection()
        cursor = conn.cursor()

        cursor.execute(query1)
        buf = cursor.fetchall()
        status = 'OFFLINE'
        if datetime.datetime.now() - buf[0][1] < datetime.timedelta(seconds=600):
            status = str(datetime.datetime.now() - buf[0][1]).split('.')[0]

        cursor.execute(query2)
        buf = cursor.fetchall()
        oper = {'1':'MTS', '2':'Megafon'}.get(str(buf[0][3]), 'N/A')
        signal = str(buf[0][2])

        params = \
        {
        'obj': obj,
        'status': status,
        'operator': oper,
        'standalone': True,
        'signal': signal,
        'error': False,
        }
    else:
        params = {'error' : True }
    return render(request, 'safeinside/one_object.html', params)

def getUnregisteredObjects(request):
    unregistered = MSLib.CarOnlineDB(dbconfig).objectsLoadUnregistered(config.get('main', 'not_registered_path'))
    params = {}
    getObjects(request, params)
    loaded_objects = params['objs_all'].objs

    for mac, entry in unregistered.iteritems():
        entry['hasRef'] = False
        if entry.has_key('msid') and (int(entry['msid']) in loaded_objects.keys()):
            entry['hasRef'] = True
            entry['ref'] = loaded_objects[int(entry['msid'])]
    params = \
    {
     'objs': unregistered,
    }
    return render(request, 'safeinside/unregistered_objects.html', params)

def objectsCountEventsByType(request, mode):
    standalone = False
    if mode == 'normal_standalone':
        standalone = True
    params = {}
    getObjects(request, 'all', params)
    loaded_objects = params['objs_all'].objs

    objs = {}
    db = MSLib.CarOnlineDB(dbconfig)
    for o in MSLib.Objects.iterateNormal(loaded_objects):
        counts = db.objectCountEventsByType(o.msid, None)
        o.counts = counts
        objs[int(o.targetid)] = o

    params = \
    {
     'objs':objs,
     'standalone':standalone,
    }
    return render(request, 'safeinside/objects_count_events_by_type.html', params)

def objectCountEventsByType(request, mode, pcnid):
    period = None
    standalone = False
    if mode == 'normal_standalone':
        standalone = True

    params = {}
    getObjects(request, 'all', params)
    loaded_objects = params['objs_all'].objs

    counts = MSLib.CarOnlineDB(dbconfig).objectCountEventsByType(obj.msid, period)
    obj.counts = counts

    params = \
    {
     'obj':obj,
     'standalone':standalone,
    }

    return render(request, 'safeinside/object_count_events_by_type.html', params)